import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * 注意：生成的公私钥对的类型为PrivateKey和PublicKey
 * 在显示和传输时，将公私钥对转化为String的Base64格式
 * 在签名和签名验证时，需将String格式的公私钥对恢复为PrivateKey和PublicKey
 * */
public class ECCKeyGen {

    // 生成 ECC 公私钥对
    public static KeyPair generateKeyPair() throws Exception {
        // 使用 EC 曲线生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
        keyPairGenerator.initialize(ecSpec);

        // 生成公私钥对
        return keyPairGenerator.generateKeyPair();
    }

    // 使用私钥对消息进行签名
    public static byte[] sign(String privateKeyStr, String message) throws Exception {
        // 将base64格式的私钥转为PrivateKey类型
        PrivateKey privateKey = base64ToPrivateKey(privateKeyStr);

        // 使用 ECDSA 签名算法
        Signature ecdsaSignature = Signature.getInstance("SHA256withECDSA");

        // 初始化签名对象，指定私钥
        ecdsaSignature.initSign(privateKey);

        // 更新签名数据
        ecdsaSignature.update(message.getBytes());

        // 执行签名
        return ecdsaSignature.sign();
    }

    // 使用公钥验证签名 (需传入签名的原消息）
    public static boolean verify(String publicKeyStr, String message, byte[] signature) throws Exception {
        // 将base64格式的私钥转为PrivateKey类型
        PublicKey publicKey = base64ToPublicKey(publicKeyStr);

        // 使用 ECDSA 签名算法进行验证
        Signature ecdsaSignature = Signature.getInstance("SHA256withECDSA");

        // 初始化验证对象，指定公钥
        ecdsaSignature.initVerify(publicKey);

        // 更新消息
        ecdsaSignature.update(message.getBytes());

        // 验证签名
        return ecdsaSignature.verify(signature);
    }

//    // 使用公钥验证签名 (不传入签名的原消息）// 该方法设计不合理
//    public static String verifyWithoutMsg(String publicKeyStr,byte[] signature) throws Exception {
//        // 将base64格式的私钥转为PrivateKey类型
//        PublicKey publicKey = base64ToPublicKey(publicKeyStr);
//
//        // 使用 ECDSA 签名算法进行验证
//        Signature ecdsaSignature = Signature.getInstance("SHA256withECDSA");
//
//        // 初始化验证对象，指定公钥
//        ecdsaSignature.initVerify(publicKey);
//
//        // 更新消息
//        ecdsaSignature.update(message.getBytes());
//
//        // 验证签名
//        return ecdsaSignature.verify(signature);
//    }






    public static void main(String[] args) {
        try {
//            // 生成 ECC 公私钥对
//            KeyPair keyPair = generateKeyPair();
//            PrivateKey sigKey = keyPair.getPrivate();
//            PublicKey pubKey = keyPair.getPublic();

//            // 将Key类型的公私钥对转为String类型
//            String sigKeyStr = encodeToBase64(sigKey.getEncoded());
//            String pubKeyStr = encodeToBase64(pubKey.getEncoded());
//            System.out.println(sigKeyStr);
//            System.out.println(pubKeyStr);

//            // 待签名的消息
//            String message = "nihao";
//
//            // 对消息进行签名
//            byte[] signature = sign(sigKey, message);
//            System.out.println("Signature: " + bytesToHex(signature));
//
//            // 验证签名
//            boolean isVerified = verify(pubKey, message, signature);
//            System.out.println("Verify?: " + isVerified);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 将字节数组转为String
    private static String encodeToBase64(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }

    // 将字节数组转换为十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    // 将私钥对转为Base64格式的字符串
    public static String privateKeyToBase64(ECPrivateKey privateKey) {
        return encodeToBase64(privateKey.getEncoded());
    }
    // 将公钥对转为Base64格式的字符串
    public static String publicKeyToBase64(ECPublicKey publicKey) {
        return encodeToBase64(publicKey.getEncoded());
    }
    // 将 Base64 编码的私钥字符串转换为 ECPrivateKey 对象   (注意ECPrivateKey为PrivateKey的一个子类）
    public static ECPrivateKey base64ToPrivateKey(String privateKeyBase64) throws Exception {
//        privateKeyBase64 = privateKeyBase64.replaceAll("\\s", "");  // 移除所有空格和换行符

        byte[] decodedKey = Base64.getDecoder().decode(privateKeyBase64);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return (ECPrivateKey) keyFactory.generatePrivate(keySpec);
    }

    // 将 Base64 编码的公钥字符串转换为 ECPublicKey 对象
    public static ECPublicKey base64ToPublicKey(String publicKeyBase64) throws Exception  {
//        publicKeyBase64 = publicKeyBase64.replaceAll("\\s", "");  // 移除所有空格和换行符

        byte[] decodedKey = Base64.getDecoder().decode(publicKeyBase64);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return (ECPublicKey) keyFactory.generatePublic(keySpec);
    }
}
